#include "SPA.h"

#include <fstream>
#include <sstream>
#include <iostream>

#include "PKB.h"
#include "Parser.h"


SPA::SPA() : _loaded( false ), _parsed( false )
{
	
}

SPA::~SPA()
{
}

void SPA::Start()
{
	/*
	Pattern pattern;
	*/
	this->FilePrompt();
	
	this->PQLPrompt();
	/*
	pattern.setupPKB(_pkb);
	vector<int> list1;
	list1.push_back(1);
	list1.push_back(2);
	list1.push_back(3);
	list1.push_back(4);
	list1.push_back(5);
	list1.push_back(6);
	list1.push_back(7);
	string var = "x";
	vector<vector<int>> result = pattern.evaluateAssign(list1,var,Pattern::LEFT_VARIABLE,"",Pattern::RIGHT_UNDERSCORE);
	for (int i=0;i<result[0].size();i++)
		cout << result[0][i] << endl;
	vector<vector<int>> result2 = pattern.evaluateAssign(list1,"",Pattern::LEFT_UNDERSCORE,"(s*x)+u",Pattern::RIGHT_EXACT_EXPRESSION);
	for (int i=0;i<result2[0].size();i++)
		cout << result2[0][i] << endl;
	vector<vector<int>> result3 = pattern.evaluateWhileIfControlVariable(list1,"z");
	for (int i=0;i<result3[0].size();i++)
		cout << result3[0][i] << endl;
		*/
}

void SPA::PQLPrompt()
{
	std::string input;
	do
	{
		std::cout << ">> ";
		std::getline( std::cin, input );

		if ( input.empty() )
			continue;

		std::list<std::string> results;
		this->EvaluateQuery( input, results );

		for_each( results.begin(), results.end(), [] ( std::string res )
		{
			std::cout << res.c_str() << " ";
		});
		std::cout << std::endl;

	} while ( input.compare( "exit" ) != 0 );
}

void SPA::FilePrompt()
{
	std::string input;
	do
	{
		_loaded = false;
		_parsed = false;

		std::cout << "Provide SIMPLE source file: ";
		std::getline( std::cin, input );

		if ( input.empty() )
			continue;

		if ( !this->LoadFile( input ) )
		{
			std::cout << "Unable to load file.\n";
			continue;
		}

		this->_loaded = true;
		std::cout << "File is loaded.\n";

		if ( !this->ParseFile() )
		{
			std::cout << "Unable to parse file.\n";
			std::cout << this->_parser.getErrorMsg() << std::endl;
			continue;
		}

		this->_parsed = true;
		std::cout << "File is parsed.\n";

		this->ExtractDesign();
		std::cout << "Design Extracted.\n";

	} while ( !this->_loaded || !this->_parsed );
}

bool SPA::LoadFile( std::string path )
{
	std::fstream file( path.c_str(), std::fstream::in );

	if ( !file.is_open() )
		return false;

	std::stringstream buffer;
	buffer << file.rdbuf();
	this->_contents = buffer.str();

	file.close();
	return true;
}

bool SPA::ParseFile()
{
	return this->_parser.parse( this->_contents );
}

void SPA::EvaluateQuery( std::string query, std::list<std::string>& results )
{
	std::list<std::string> res = this->_query_processor.Process( query );

	std::for_each( res.begin(), res.end(), [ &results ] ( std::string str )
	{	
		results.push_back( str );
		//std::cout << str.c_str() << " ";
	});
	//std::cout << std::endl;
}

void SPA::ExtractDesign()
{
	this->_design_extractor.ExtractDesign();
	this->_query_processor.PreparePreprocessor();
	PKB::nextbip.computeNextBIP();
}

bool SPA::CompareGeneratedCode()
{
	this->_parser.displayProcedure( PKB::ast.GetRoot( 0 ) );
	return ( this->_contents.compare( this->_parser.getCodeList() ) == 0 );
}